//
//  ViewController.m
//  gcd所有的代码测试
//
//  Created by 杨庆 on 16/1/7.
//  Copyright © 2016年 双元班. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
//清空内存的缓存的方法!
    
}
/// 队列的创建
-(void)queue{
    //串行队列的创建
    dispatch_queue_t queue = dispatch_queue_create("queue name", DISPATCH_QUEUE_SERIAL);
    //或者是 :
    dispatch_queue_t queue2 = dispatch_queue_create("queue name2", NULL);
    //并发队列的创建
    dispatch_queue_t queue3 = dispatch_queue_create("queue name3", DISPATCH_QUEUE_CONCURRENT);
    //主队列的创建和它的特点
    //主队列是只负责在主线程上调度任务的
    //主队列是不会再开辟新的线程的
    dispatch_queue_t queue4 = dispatch_get_main_queue();
    //当我们的主队列 遇上 异步队列的情况:(他不会造成死锁);他等待那个主队列上的所有的任务完成之后的话,就会才来执行!
    
    //主队列遇到同步任务的时候:(会造成死锁的情况) 他这个是主队列和主线程之间进行的相互的等待!
    dispatch_sync(queue4, ^{
        NSLog(@"这个是在主线程的环境下:主队列遇到同步的任务会造成死锁的情况");
    });
}

/// 全局的队列--->异步执行操作
//全局的队列是 系统为了方便开发提供的一个 "类似并发的队列"的操作!
//全局队列和并发队列的区别是 :  全局队列没有名字,不管是MRC 或者是 ARC下都不需要考虑释放的问题!而并发队列的话是都要考虑
-(void)gcdDemo1{
    //1.创建队列(创建了一个主队列)
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //2.创建任务(gcd是应用的一个block)
    void(^task)() = ^{
        NSLog(@"主队列执行的任务");
    };
    //3.添加异步执行的操作
    dispatch_async(queue, task);
//以上的是应用gcd 来执行的异步操作的代码实现
}

/// 线程之间的通信,异步完成之后的话:我们要求来主线程更新UI的操作;
-(void)gcdDemo2{
    //1.异步线程的下载的操作;
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //进行的耗时的操作!
        NSLog(@"耗时的下载操作  %@",[NSThread currentThread]);
        //回到主线程来更新UI
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"回到主线程更新UI  %@",[NSThread currentThread]);
        });
        //还需要在主线程继续执行的代码:
        NSLog(@"继续主线程执行的代码");
    });
}

/// 主队列遇到同步的任务不会死锁的情况
-(void)gcdDemo3{
    dispatch_queue_t queue = dispatch_queue_create("zhuduiliebusisuo", DISPATCH_QUEUE_CONCURRENT);
    void(^task)() = ^{
        NSLog(@"添加同步任务的情况");
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"会死锁ma");
        });
    };
    //最后的话,就是要将我们的整个的操作放在子线程来进行的完成!这样的话就会避免我们的整个操作的环境是在异步的情况来完成的..这样的话就不会造成死锁了...明白吗!
    dispatch_async(queue, task);
    //加上了之后的原因是: 我们的主队列在`主线程空闲时`才会调度队列中的任务在主线程执行
}

/// 经典的案例的实现
//同步的任务可以让其他的异步的任务来,依赖 某一个同步任务
-(void)gcdDemo4{
    //先创建一个并发队列(都是再 并发队列的情况下来完成和实现的)
    dispatch_queue_t queue = dispatch_queue_create("yilai", DISPATCH_QUEUE_CONCURRENT);
    //一步步的进行任务的添加
    dispatch_sync(queue, ^{
        NSLog(@"先进行的用户的登录的操作");
    });
    dispatch_async(queue, ^{
        NSLog(@"A: 异步的下载");
    });
    dispatch_async(queue, ^{
        NSLog(@"B: 异步的下载2");
    });
    //这样的话;A B 就依赖我们的同步任务了!
    //还有一种的讲所有的操作都移动到我们异步的操作当中来:
    void(^task)() = ^{
        dispatch_sync(queue, ^{
            NSLog(@"先进行的用户的登录的操作");
        });
        dispatch_async(queue, ^{
            NSLog(@"A: 异步的下载");
        });
        dispatch_async(queue, ^{
            NSLog(@"B: 异步的下载2");
        });
    };
    //最后的话,整体的添加到我们的异步操作中来完成明白吗!!!
    dispatch_async(queue, task);
}

/// 调度组的实现(重点)
//最常规的用法,要求掌握的
-(void)gcdDemo5{
    //1.创建调度组,记住的是 group_create
    dispatch_group_t group = dispatch_group_create();
    //2.创建队列: 要求的是创建一个最好用的队列就是: get_goalo_queue
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //3.将任务添加到队列和调度组,这两个都不可少的情况!(就是类比的话将大数据的多开线程来解决)
    dispatch_group_async(group, queue, ^{
        NSLog(@"要执行的任务1");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"要执行的任务2");
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"要执行的任务3");
    });
    //4.监听所有的操作是否完成了
    dispatch_group_notify(group, queue, ^{
        NSLog(@"所有的任务,全部的完成了");
    });
}

@end
